package com.itheima.health.config;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.web.cors.CorsConfiguration;

import java.io.IOException;

/**
 * Spring Security 配置类。
 * 该类用于配置Spring Security的安全过滤规则、登录/登出处理、权限控制等。
 */
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true) // 启用 @PreAuthorize 和 @PostAuthorize 注解
public class SecurityConfig {

    /**
     * 配置安全过滤规则。
     * @param http HttpSecurity对象，用于配置安全规则。
     * @return 返回配置好的SecurityFilterChain。
     * @throws Exception 可能抛出的异常。
     */
    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                // 允许跨域请求
                .cors(cors -> cors.configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues()))
                // 禁用csrf 跨域攻击
                .csrf(csrf -> csrf.disable())
                // 配置权限
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/front/**", "/login.do", "/logout.do").permitAll()  // 允许所有人访问/login.do路径
                        .requestMatchers("/backend/pages/**").authenticated()  // 对 /pages/** 进行权限控制，需要已认证用户
                        .requestMatchers("/backend/**").permitAll()  // 放行 backend 下除 pages 外的所有资源
                        .anyRequest().authenticated() // 其他请求需要登录
                )
                // 配置表单登录
                .formLogin(form -> form
                        .loginProcessingUrl("/login.do")// 登录地址
                        .loginPage("/backend/login.html") // 自定义登录页地址
                        .permitAll() // 允许所有人访问登录页
                        .successHandler(new AuthenticationSuccessHandler() {
                            @Override
                            public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                                // 登录成功后的处理逻辑
                                response.sendRedirect("/backend/pages/main.html");
                            }
                        })
                        // 登录失败后的处理逻辑
                        .failureHandler(new AuthenticationFailureHandler() {
                            @Override
                            public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, org.springframework.security.core.AuthenticationException exception) throws IOException, ServletException {
                                // 登录失败后的处理逻辑
                                response.sendRedirect("/backend/login.html?error=true");
                            }
                        })
                )
                // 配置登出
                .logout(logout -> logout
                        .logoutUrl("/logout.do") // 退出登录地址
                        .logoutSuccessHandler(new LogoutSuccessHandler() {
                            @Override
                            public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, org.springframework.security.core.Authentication authentication) throws IOException, ServletException {
                                // 登出成功后的处理逻辑
                                response.sendRedirect("/backend/login.html");
                            }
                        })
                )
                // 添加自定义的安全头禁用（可选）
                .headers(headers -> headers
                        .addHeaderWriter((request, response) -> response.setHeader("X-Frame-Options", "SAMEORIGIN")) // 允许同源iframe嵌入
                );
        // 异常处理
//                .exceptionHandling(exception -> exception
//                        .accessDeniedHandler(new AccessDeniedHandler() {
//                            @Override
//                            public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
//                                // 访问被拒绝时的处理逻辑
//                                response.sendRedirect("/backend/login.html?error=access_denied");
//                            }
//                        })
//                );

        return http.build();
    }

    /**
     * 密码加密器。
     * @return 返回一个BCryptPasswordEncoder实例。
     */
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 认证管理器。
     * @param authenticationConfiguration 认证配置。
     * @return 返回一个AuthenticationManager实例。
     * @throws Exception 可能抛出的异常。
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        // 获取认证管理器
        return authenticationConfiguration.getAuthenticationManager();
    }
}